﻿using ASmile.Com;
using ASmile.Extend;
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace ASmile.Win.Extend
{
    public static class TreeViewExFunc
    {
        /// <summary>
        /// 循环遍历所有节点及子节点，当满足 FindHandle 时退出
        /// </summary>
        /// <param name="tv">treeview控件</param>
        /// <param name="FindHandle">终止条件，为空时遍历所有节点返回false</param>
        /// <returns>findHandle成立时返回true</returns>
        public static bool LoopTreeNode(this TreeView tv, Func<TreeNode, bool> FindHandle)
        {
            foreach (TreeNode node in tv.Nodes)
            {
                if (LoopTreeNode(node, FindHandle))
                {
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 循环树节点，当findHandle返回true是退出，返回false则遍历全部
        /// </summary>
        /// <param name="rootNode">要遍历的主节点</param>
        /// <param name="FindHandle">找到节点的委托方法</param>
        /// <returns>FindHandle 的返回值</returns>
        public static bool LoopTreeNode(this TreeNode rootNode, Func<TreeNode, bool> FindHandle)
        {
            foreach (TreeNode node in rootNode.Nodes)
            {
                if (FindHandle?.Invoke(node) == true)
                {
                    return true;
                }
                else
                {
                    if (LoopTreeNode(node, FindHandle))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// 初始化TreeView数据
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="tv">树控件</param>
        /// <param name="treeData">数据</param>
        /// <param name="IsRootNode">是否主节点的委托方法</param>
        /// <param name="IsSubNode">是否子节点的委托方法</param>
        /// <param name="CreateNode">创建节点的委托方法</param>
        public static void InitTreeViewData<T>(
            this TreeView tv,
            IEnumerable<T> treeData,
            Func<T, bool> IsRootNode,
            Func<T, TreeNode, bool> IsSubNode,
            Func<T, TreeNode> CreateNode
            )
        {
            tv.Nodes.Clear();

            if (treeData == null) return;

            foreach (var item in treeData)
            {
                if (IsRootNode(item))
                {
                    TreeNode tn = CreateNode(item);
                    tv.Nodes.Add(tn);
                    LoadSubMenu(tn);
                }
            }

            void LoadSubMenu(TreeNode pNode)
            {
                foreach (var item in treeData)
                {
                    if (IsSubNode(item, pNode))
                    {
                        TreeNode tn = CreateNode(item);
                        pNode.Nodes.Add(tn);
                        LoadSubMenu(tn);
                    }
                }
            }
        }

        /// <summary>
        /// 初始化菜单树
        /// </summary>
        public static void InitTreeViewData<TData>(this TreeView tv, IEnumerable<TData> treeData, Func<TData, bool> CheckRootNode, Action<TreeNode, TData> OnNodeAdded = null)
            where TData : ITreeModel
        {
            if (CheckRootNode == null)
            {
                CheckRootNode = IsRootNode;
            }

            tv.InitTreeViewData(treeData, CheckRootNode, IsSubNode, CreateNode);

            bool IsRootNode(TData m)
            {
                return m.PId.IsEmpty();
            }
            bool IsSubNode(TData m, TreeNode pNode)
            {
                return m.PId == pNode.Name;
            }
            TreeNode CreateNode(TData model)
            {
                TreeNode tn = new TreeNode();
                tn.Name = model.Id;
                tn.Text = model.Caption;
                tn.Tag = model;
                OnNodeAdded?.Invoke(tn, model);
                return tn;
            }
        }

        public static void InitTreeViewData<TData>(this TreeView tv, IEnumerable<TData> treeData, Action<TreeNode, TData> OnNodeAdded = null)
            where TData : ITreeModel
        {
            InitTreeViewData(tv, treeData, null, OnNodeAdded);
        }
    }
}